package com.xdf.whiteaccount.service.impl;

import com.xdf.whiteaccount.dao.CpBillfhMapper;
import com.xdf.whiteaccount.entity.CpBillfh;
import com.xdf.whiteaccount.entity.ScanList;
import com.xdf.whiteaccount.enums.ScanQrCategory;
import com.xdf.whiteaccount.service.GjrkbillCpService;
import com.xdf.whiteaccount.service.ScanListService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.context.annotation.Lazy;
import com.xdf.whiteaccount.dao.GjrkbillCpMapper;
import com.xdf.whiteaccount.entity.GjrkbillCp;
import com.xdf.whiteaccount.utils.BusinessException;
import com.xdf.whiteaccount.utils.Example;
import com.xdf.whiteaccount.utils.BeanUtils;
import com.xdf.whiteaccount.enums.OpeEnum;
import com.xdf.whiteaccount.enums.MoveBillFlag;

/**
 * @Description : 服务层实现类，由代码生成器自动生成
 * @Author : chanchaw
 * @Date : 2023-12-1 10:11:33
 */
@Slf4j
@Service
public class GjrkbillCpServiceImpl implements GjrkbillCpService {
    @Autowired
    private GjrkbillCpMapper dao;

    @Lazy
    @Autowired
    private GjrkbillCpServiceImpl meService;
    @Autowired
    private ScanListService scanListService;
    @Autowired
    private CpBillfhMapper cpBillfhMapper;

    @Override
    @Transactional
    public GjrkbillCp insert(GjrkbillCp record) {
        record = meService.fullFill(record);
        meService.doBeforeInsert(record);
        dao.insert(record);
        meService.doAfterInsert(record);
        return record;
    }

    @Override
    @Transactional
    public GjrkbillCp insertSelective(GjrkbillCp record) {
        record = meService.fullFill(record);
        meService.doBeforeInsert(record);
        dao.insertSelective(record);
        meService.doAfterInsert(record);
        return record;
    }

    /* 由于本方法无法返回所有对象的自增主键，后者调整为一个一个保存的方法
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int multiInsert(List<GjrkbillCp> list) {
        return dao.multiInsert(list);
    }
     */
    @Override
    @Transactional
    public List<GjrkbillCp> multiInsert(List<GjrkbillCp> list) {
        list.forEach(item -> meService.insertSelective(item));
        return list;
    }

    @Override
    public int updateByPrimaryKey(GjrkbillCp record) {
        try {
            BeanUtils.fullFillRecord(record, OpeEnum.UPDATE);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return dao.updateByPrimaryKey(record);
    }

    @Override
    public int updateByPrimaryKeySelective(GjrkbillCp record) {
        try {
            BeanUtils.fullFillRecord(record, OpeEnum.UPDATE);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return dao.updateByPrimaryKeySelective(record);
    }

    @Override
    public int deleteByPrimaryKey(Integer B_ItemID) {
//        GjrkbillCp dbRecord = dao.selectByPrimaryKey(B_ItemID);
//        if( dbRecord == null ) return 0;
//        dbRecord.setState(-1);
//        return dao.updateByPrimaryKey(dbRecord);
        return dao.deleteByPrimaryKey(B_ItemID);
    }

    @Override
    public GjrkbillCp selectByPrimaryKey(Integer B_ItemID) {
        return dao.selectByPrimaryKey(B_ItemID);
    }

    // 根据主键作废
    @Override
    public int setVoid(Integer B_ItemID){
//        GjrkbillCp dbRecord = dao.selectByPrimaryKey(B_ItemID);
//        if( dbRecord == null ) return 0;
//        dbRecord.setState(0);
//        return dao.updateByPrimaryKey(dbRecord);
        return dao.deleteByPrimaryKey(B_ItemID);
    }

    @Override
    public List<GjrkbillCp> selectAll(){
        return dao.selectAll();
    }

    @Override
    public GjrkbillCp save(GjrkbillCp record){
        if(record == null) throw new BusinessException("空对象不可保存！");
        Integer iid = Optional.ofNullable(record.getBItemID()).orElse(0);
        if(iid==0) record = insertSelective(record);
        else updateByPrimaryKeySelective(record);
        return record;
    }

    // 没有使用 xml 中的 multiSave 方法是因为无法批量回写自增主键
    @Transactional
    @Override
    public List<GjrkbillCp> multiSave(List<GjrkbillCp> list){
        if(list == null || list.size()==0) return list;
        list.forEach(item -> item = meService.save(item));
        return list;
    }

    /**=========================下面开始是固定模式代码=======================================*/
    // 新增前检测，不可新增则抛出异常
    private void check4Insert(GjrkbillCp record){
    }

    @Override
    public GjrkbillCp fullFill(GjrkbillCp record) {
        // TODO: 默认前端传递来的参数不需要填充完整，如果需要则使用自定义逻辑覆盖下面的代码
        try {
            // 根据“新增”或者“修改”填充创建人或者最后一次修改人
            // 要求表格中有字段：create_user,last_user
            BeanUtils.fullFillRecord(record,OpeEnum.NEW);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return record;
    }

    @Override
    public void doBeforeInsert(GjrkbillCp record) {
        // TODO: 在新增数据前需要做的逻辑写在这里，抛出异常则终止新增操作
        GjrkbillCpService.super.doBeforeInsert(record);
    }

    @Override
    public void doAfterInsert(GjrkbillCp record) {
        // TODO: 新增数据后需要做的逻辑写在这里，抛出异常则终止新增操作
        GjrkbillCpService.super.doAfterInsert(record);
    }

    @Override
    public List<GjrkbillCp> selectByExample(Example<GjrkbillCp> example){
        return dao.selectByExample(example);
    }

    @Override
    public GjrkbillCp moveBill(Integer id, String moveBillFlag){
        if(moveBillFlag.equalsIgnoreCase(MoveBillFlag.FIRST.getFlag())){
            GjrkbillCp first = dao.getFirst();
            if(first == null) throw new BusinessException("没有单据！");
            else return first;
        }

        if(moveBillFlag.equalsIgnoreCase(MoveBillFlag.LAST.getFlag())){
            GjrkbillCp last = dao.getLast();
            if(last == null) throw new BusinessException("没有单据！");
            else return last;
        }
        if(moveBillFlag.equalsIgnoreCase(MoveBillFlag.NEXT.getFlag())){
            GjrkbillCp next = dao.getNext(id);
            if(next == null) throw new BusinessException("没有下一单了！");
            else return next;
        }

        if(moveBillFlag.equalsIgnoreCase(MoveBillFlag.PREVIOUS.getFlag())){
            GjrkbillCp prev = dao.getPrev(id);
            if(prev == null) throw new BusinessException("没有上一单了！");
            else return prev;
        }

        return null;
        }
    //=================以上是自动生成的代码，自定义代码请写在下面==================

    @Override
    public List<GjrkbillCp> selectByPrimaryKeyList(List<Integer> idList){
        return dao.selectByPrimaryKeyList(idList);
    }

    /**
     * 先修改字段 b_upload为设备编号，再返回给前端
     * @param jrkId = g_jrkbill_cp.B_jrkbilldraftitemid
     * @param deviceId
     * @return
     */
    @Transactional
    @Override
    public GjrkbillCp scanOneQR(Integer jrkId, Integer deviceId){
        if(deviceId == null) throw new BusinessException("没有设备编号，无法扫描！");

        Example example = new Example().andEq("B_jrkbilldraftitemid", jrkId);
        List<GjrkbillCp> gjrkbillCpList = dao.selectByExample(example);
        if(gjrkbillCpList == null || gjrkbillCpList.size() == 0) throw new BusinessException("这匹布不存在系统中！");

        // 返回当前可用的数据 - 同时满足：没有扫描、没有发货。
        List<GjrkbillCp> collect = gjrkbillCpList.stream().filter(item ->
                        Optional.ofNullable(item.getBFPDID()).orElse(0).equals(0)
                    && Optional.ofNullable(item.getBUpload()).orElse(0).equals(0))
                .collect(Collectors.toList());

        // 检测异常：
        // 1. 没有数据则表示该数据已经扫描或者已经发货
        // 2. 有多笔数据表示有重复数据
        if(collect.size() == 0) throw new BusinessException("已扫描或已发货不可重复操作！");
        if(collect.size() > 1) throw new BusinessException("同一个二维码有多个未发货数据，请联系开发人员排查异常！");

        // 写入扫描记录并获得自增的主键写入打卷表中
        ScanList scanQrOne = scanListService.insertSelectiveOne(jrkId, deviceId);
        Integer scanId = Optional.ofNullable(scanQrOne.getId()).orElse(0);

        // 写入扫描标记
        GjrkbillCp gjrkbillCp = collect.get(0);
        gjrkbillCp.setBUpload(deviceId);
        gjrkbillCp.setScanId(scanId);
        dao.updateByPrimaryKeySelective(gjrkbillCp);
        return gjrkbillCp;
    }

    /**
     * 扫描货架号返回其下所有打卷明细数据
     * @param barcode
     * @param deviceId
     * @return
     */
    @Override
    public List<GjrkbillCp> scanShelvesQR(String barcode, Integer deviceId){
        if(deviceId == null) throw new BusinessException("没有设备编号，无法扫描！");
        // 排除已经单独扫描过的单匹数据
        Example example = new Example().andEq("b_barcode", barcode).andEq("scan_id",0);
        List<GjrkbillCp> gjrkbillCpList = dao.selectByExample(example);

        // 返回当前可用的数据 - 同时满足：没有扫描、没有发货。
        List<GjrkbillCp> collect = gjrkbillCpList.stream().filter(item ->
                        Optional.ofNullable(item.getBFPDID()).orElse(0).equals(0)
                    && Optional.ofNullable(item.getBUpload()).orElse(0).equals(0))
                .collect(Collectors.toList());
        if(collect == null || collect.size() == 0) throw new BusinessException("本货架全部产品都已发货！");

        // 写入扫描记录并获得自增的主键写入打卷表中
        ScanList scanRecord = scanListService.insertSelectiveShelves(barcode, deviceId);
        Integer scanId = Optional.ofNullable(scanRecord.getId()).orElse(0);

        collect.forEach(item -> {
            item.setBUpload(deviceId);
            item.setScanId(scanId);
            dao.updateByPrimaryKeySelective(item);
        });
        return collect;
    }

    /**
     * 根据货架号更新设备编号字段 b_upload
     * @param barcode
     * @return
     */
    @Override
    public int updateDeviceId8ShelvesQR(String barcode, Integer deviceId){
        GjrkbillCp gjrkbillCp = new GjrkbillCp();
        gjrkbillCp.setBUpload(deviceId);
        Example example = new Example().andEq("b_barcode", barcode);
        return dao.updateByExampleSelective(gjrkbillCp,example);
    }

    @Override
    public boolean prepared4FH(GjrkbillCp record){
        Integer bfpdid = Optional.ofNullable(record.getBFPDID()).orElse(0);
        Integer bUpload = Optional.ofNullable(record.getBUpload()).orElse(0);
        return bfpdid.equals(0) && bUpload.equals(0);
    }

    /**
     * 取消打卷表中设备编号的同时取消扫描流水ID
     * @param id
     * @return
     */
    @Override
    public int clearPDADeviceId8PrimaryKey(Integer id){
        Example example = new Example().andEq("B_jrkbilldraftitemid", id);
        List<GjrkbillCp> gjrkbillCps = dao.selectByExample(example);
        if(gjrkbillCps == null || gjrkbillCps.size() == 0) return 0;

        gjrkbillCps.forEach(item -> {
            item.setBUpload(0);
            item.setScanId(0);
            dao.updateByPrimaryKey(item);
        });
        return 1;
    }

    /**
     * 取消打卷表中设备编号的同时取消扫描流水ID
     * @param barcode
     * @return
     */
    @Override
    public int clearPDADeviceId8Barcode(String barcode){
        Example example = new Example().andEq("b_barcode", barcode);
        GjrkbillCp gjrkbillCp = new GjrkbillCp();
        gjrkbillCp.setBUpload(0);
        gjrkbillCp.setScanId(0);
        return dao.updateByExampleSelective(gjrkbillCp, example);
    }

    /**
     * 清除发货标记的要关联做的清除工作：
     * 1. 清除扫描的设备编号 g_jrkbill_cp.B_upload
     * 2. 清除扫描的流水号 g_jrkbill_cp.scan_id
     * @param cpBillfhId
     * @return
     */
    @Transactional
    @Override
    public int clearFPDIDBatch(Integer cpBillfhId){
        Example example = new Example().andEq("B_FPDID", cpBillfhId);
        GjrkbillCp gjrkbillCp = new GjrkbillCp();
        gjrkbillCp.setBUpload(0);
        gjrkbillCp.setScanId(0);
        dao.updateByExampleSelective(gjrkbillCp,example);
        return dao.clearFPDID(cpBillfhId);
    }

    /**
     * 从发货单中剔除一匹：
     * 1. 清除发货单外键
     * 2. 清除扫描设备编号
     * 3. 清除扫描流水号
     * 4. 重新统计匹数、公斤、米数
     * @param jrkId 成品打卷表主键 = g_jrkbill_cp.B_ItemID
     * @return
     */
    @Transactional
    @Override
    public int clearFPDIDOne(Integer jrkId){
        GjrkbillCp gjrkbillCp = dao.selectByPrimaryKey(jrkId);
        if(gjrkbillCp == null) throw new BusinessException("没有找到主键" + jrkId + "的打卷数据！");
        Integer bfpdid = Optional.ofNullable(gjrkbillCp.getBFPDID()).orElse(0);// 发货单主键
        gjrkbillCp.setBUpload(0);// 扫描的设备编号
        gjrkbillCp.setScanId(0);// 扫描流水号
        gjrkbillCp.setBFPDID(0);// 发货单外键

        // 先清除再统计
        int i = dao.updateByPrimaryKeySelective(gjrkbillCp);

        // 修改发货单统计数据
        CpBillfh cpBillfh = cpBillfhMapper.collectJrk8Id(bfpdid);
        cpBillfhMapper.updateByPrimaryKeySelective(cpBillfh);

        return i;
    }

    /**
     * 清除成品打卷表 g_jrkbill_cp 中扫描的设备ID
     * @param scanId
     * @return
     */
    @Transactional
    @Override
    public int clearPDADeviceId8ScanId(Integer scanId){
        if(scanId == null) throw new BusinessException("扫描流水ID不可为空！");
        Example example = new Example().andEq("scan_id", scanId);
        List<GjrkbillCp> gjrkbillCps = dao.selectByExample(example);
        for (GjrkbillCp item : gjrkbillCps) {
            item.setBUpload(0);
            item.setScanId(0);
            dao.updateByPrimaryKeySelective(item);
        }

        return 1;
    }
}